
/*							*/
/*  Indexed Sequential Access Method			*/
/*  Relational Database Systems, Inc.			*/
/*							*/
/*		Proprietary Data			*/
/*    This document contains proprietary information	*/
/* and trade secrets which are the property of		*/
/* Relational Database Systems, Inc. (RDSI). This	*/
/* document is submitted to recipient in confidence.	*/
/* The information contained herein may not be used,	*/
/* copied or disclosed in whole or in part except as	*/
/* permitted by written agreement signed by an officer	*/
/* of RDSI.						*/
/*							*/

/*
 * support routines
 *
 * Relational Database Systems, Inc.
 * Roy Harrington	November 4, 1981
 *
 *  06-07-83  RVH	V104 -- added kernel modifications
 *  08-24-83  RVH	V105 -- dynamic memory allocation
 */

#include "isdec.c"

#ifndef ISKERNEL
#define fubyte(p)	(*(p))
#define subyte(p,c)	(*(p)=(c))
#endif  /* ISKERNEL */

/*
 * allocate an open file entry
 * returns isfd
 */

STATIC int allocopen()
{
	register int isfd;

	for (isfd=0; isfd<nopens; isfd++)
	    {
	    openp = opens[isfd];
#ifdef ISALLOC					/* dynamic allocation	*/
	    if (openp == NULL)			/* V105	*/
		{
		opens[isfd] = openp =
			(struct open *) malloc(sizeof(struct open));
		if (openp == NULL)
		    goto bad;
		openp->o_flags = 0;
		}
#else
	    if (openp == NULL)			/* static allocation	*/
		opens[isfd] = openp = &opentab[isfd];
#endif /* ISALLOC */
	    if (openp->o_flags == 0)		/* find free open	*/
		{
		byfill(CASTCP openp, sizeof(struct open), 0);
		openp->o_procid = getpid();
		openp->o_userid = getuid();
		openp->o_flags = OBUSY;
		return(isfd);
		}
	    openp++;
	    }
bad:
	iserrno = ETOOMANY;
	return(-1);
}

STATIC int freeopen(op)
register struct open *op;
{
	if (op->o_filep != NULL)
	    freefile(op->o_filep);		/* free file struct	*/
	openp->o_flags = 0;
}


/*
 * allocate a isam file block
 */

STATIC struct ifile *allocfile(filename, mode)
char *filename;		/* V104 -- NOTE: for kernel this is array of ptrs */
register int mode;
{
	register struct ifile *fp, *zfp;
	register int i;
	dev_t filedev;		/*new fileid*/
	ino_t fileno;
	/*long fileid */
#ifdef ISKERNEL
	char *fname;
#else
	char fname[PATHSIZE];
#endif /* ISKERNEL */

	mkidxname(filename, fname);
	/*new fileid*/
	if (getfileid(fname, &filedev, &fileno))  
	    return(NULL);

	zfp = NULL;

	for (i=0; i<nfiles; i++)
	    {
	    fp = files[i];			/* search for existing	*/
#ifdef ISALLOC
	    if (fp == NULL)			/* dynamic allocation	*/
		{
		files[i] = fp =
			(struct ifile *) malloc(sizeof(struct ifile));
		if (fp == NULL) break;
		fp->f_ucount = 0;
		}
#else
	    if (fp == NULL)			/* static allocation	*/
		files[i] = fp = &filetab[i];
#endif /* ISALLOC */
	    if (fp->f_ucount > 0 && fp->f_inum == fileno &&
		fp->f_device == filedev)
		goto found;			/* match fileid		*/
	    if (zfp == NULL && fp->f_ucount == 0)
		zfp = fp;			/* save empty one	*/
	    }

	if (zfp == NULL)
	    {
	    iserrno = ETOOMANY;
	    return(NULL);
	    }

	fp = zfp;				/* use empty one	*/
	byfill(CASTCP fp, sizeof(struct ifile), 0);

	i = RWMODE;
idxagain:
	if ((fp->f_idxfd = open(fname, i)) == -1)
	    {
#ifndef ZILOG				/* zilog locking requires RWMODE */
	    if (errno == EACCES && i == RWMODE && mode == ISINPUT)
		{
		i = RMODE;
		goto idxagain;
		}
#endif /* not ZILOG */
	    iserrno = errno;
	    iserrio = IO_OPEN+IO_IDX;
	    return(NULL);
	    }

	mkdatname(filename, fname);
	i = RWMODE;
datagain:
	if ((fp->f_datfd = open(fname, i)) == -1)
	    {
	    if (errno == EACCES && i == RWMODE && mode == ISINPUT)
		{
		i = RMODE;
		goto datagain;
		}
	    iserrno = errno;
	    iserrio = IO_OPEN+IO_DAT;
	    VOID close(fp->f_idxfd);
	    return(NULL);
	    }

#ifdef CREATLOCK
	mklokname(filename, fname);
	if ((fp->f_lokfd = open(fname, RWMODE)) == -1)
	    {
	    iserrno = errno;
	    iserrio = IO_OPEN+IO_LOK;
	    VOID close(fp->f_idxfd);
	    VOID close(fp->f_datfd);
	    return(NULL);
	    }
#endif

	fp->f_device = filedev;
	fp->f_inum = fileno;
#ifdef SEMPHLOCK
	initsem(fp);
#endif /* SEMPHLOCK */

found:
	fp->f_ucount++;
	return(fp);
}

STATIC int freefile(fp)
register struct ifile *fp;
{
	if (--fp->f_ucount) return;		/* still in use		*/

	bfignor(filep);
	if (fp->f_flags & FAUDOPEN)
	    VOID close(fp->f_audfd);
	fp->f_flags = 0;			/* deallocate table	*/

	/*new fileid*/
	fp->f_device = -1;
	fp->f_inum = -1;

	VOID close(fp->f_idxfd);
	VOID close(fp->f_datfd);
#ifdef CREATLOCK
	VOID close(fp->f_lokfd);
#endif
}

#ifdef SEMPHLOCK
/*
 * for SYSTEM V semaphores, initialize info
 */

initsem(fp)
struct ifile *fp;
{
	register int semid;
	key_t key;

	key = 0xDB000000L + (fp->f_device << 16) + fp->f_inum;

retry:
	semid = semget(key, 1, 0666);
	if (semid == -1 && errno == ENOENT)
	    {
	    semid = semget(key, 1, IPC_CREAT|IPC_EXCL|0666);
	    if (semid == -1 && errno == EEXIST)
		goto retry;
	    if (semid >= 0 && semctl(semid, 0, SETVAL, 1) == -1)
		semid = -1;
	    }
	fp->f_semid = semid;
}
#endif /* SEMPHLOCK */

/*
 * allocate index or data record
 */

STATIC long allocrec(flag)
int flag;
{
	register struct buff *bp;
	register char *freep, *nextp;
	long node, node2;

	if (flag == INDXREC)			/* INDXREC or DATAREC	*/
	    {
	    freep = dictp->d_freenode;
	    nextp = dictp->d_nextnode;
	    }
	else
	    {
	    freep = dictp->d_freedata;
	    nextp = dictp->d_nextdata;
	    }

next:
	node = ld4(freep);
	if (node == 0)				/* no free nodes	*/
	    {
extend:	    node = ld4(nextp) + 1L;
	    st4(node, nextp);			/* extend file		*/
	    filep->f_dicbp->bf_flags |= BFMODF;	/* dictionary modified	*/
	    }
	else
	    {
	    bp = bfread(node);			/* get free list	*/
	    if (bp == NULL) goto extend;
	    bp->bf_used -= 4;			/* get next free node	*/
	    node2 = ld4(bp->bf_un.bf_addr+bp->bf_used);
	    if (bp->bf_used <= 2)
		{
		st4(node2, freep);
		filep->f_dicbp->bf_flags |= BFMODF;
		if (flag != INDXREC)
		    {
		    bfrelease(bp);
		    freerec(node, INDXREC);	/* free index record	*/
		    goto next;
		    }
		}
	    else
		{
		node = node2;
		}
	    bfdwrite(bp);
	    }
	return(node);
}

/*
 * free index or data record
 */

STATIC int freerec(node, flag)
long node;
int flag;
{
	register struct buff *bp;
	register char *freep, *nextp;
	long fnode, node2;

	if (flag == INDXREC)			/* INDXREC or DATAREC	*/
	    {
	    freep = dictp->d_freenode;
	    nextp = dictp->d_nextnode;
	    }
	else
	    {
	    freep = dictp->d_freedata;
	    nextp = dictp->d_nextdata;
	    }

	if (node == ld4(nextp))			/* freeing last record ?*/
	    {
	    node--;
	    st4(node, nextp);			/* yes, just shrink file*/
	    filep->f_dicbp->bf_flags |= BFMODF;
	    return;
	    }

	fnode = ld4(freep);
	if (fnode == 0)				/* no free list ?	*/
	    {
newfree:
	    if (flag != INDXREC)
		node2 = allocrec(INDXREC);
	    else node2 = node;

	    st4(node2, freep);			/* create free list	*/
	    filep->f_dicbp->bf_flags |= BFMODF;	/* dictionary modified	*/
	    bp = bfgetclr(node2);
	    bp->bf_used = 6;
	    bp->bf_level = 0x7F;
	    bp->bf_type = (flag == INDXREC)? 0xFE: 0xFF;
	    st4(fnode, bp->bf_un.bf_free->fn_next);
	    if (flag != INDXREC)
		{
		st4(node, bp->bf_un.bf_addr+6);	/* store free node	*/
		bp->bf_used = 10;
		}
	    bfdwrite(bp);
	    }
	else
	    {
	    bp = bfread(fnode);			/* get free list	*/
	    if (bp == NULL) return;
	    if (bp->bf_used+4 < filep->f_idxsize-2)
		{
		st4(node, bp->bf_un.bf_addr+bp->bf_used);
		bp->bf_used += 4;
		}
	    else
		{
		bfrelease(bp);
		goto newfree;
		}
	    bfdwrite(bp);
	    }
}

#ifndef ISKERNEL	/* V104 */
/*
 * make a new file
 */

STATIC int makefile(fname)
register char *fname;
{
	register int fd;

	errno = EEXIST;
	if ((fd = open(fname, RWMODE)) != -1 || errno != ENOENT)
	    goto bad;				/* file already exist ?	*/

	if ((fd = creat(fname, CREATMODE)) == -1)
	    goto bad;				/* create file		*/

	VOID close(fd);
	return(0);
bad:
	iserrno = errno;			/* system error		*/
	if (fd != -1) VOID close(fd);
	return(-1);
}
#endif


#ifndef MPM86
#ifndef PCDOS
#ifndef ISKERNEL


/*
 * return unique file identifier
 */

STATIC int getfileid(fname, devp, inump)
char *fname;
dev_t *devp;	/*new fileid*/
ino_t *inump;
{
	struct stat st;

	if (stat(fname, &st))
	    {
	    iserrno = errno;
	    return(-1);
	    }
	else
	    {
	    *devp = st.st_dev;
	    *inump = st.st_ino;
	    return(0);
	    }
}

#else /* ISKERNEL */

STATIC int getfileid(fname, devp, inump)
char *fname;
dev_t *devp;
ino_t *inump;
{
	register struct inode *fd;

	if ((fd = open(fname, RMODE)) == -1)
	    return(-1);
	*devp = fd->i_dev;
	*inump = fd->i_number;
	close(fd);
	return(0);
}
#endif /* ISKERNEL */
#endif /* not PCDOS */
#endif /* not MPM86 */


/*
 * read a data record into "record"
 */

STATIC int dataread(record, recnum)

register char *record;
long recnum;
{
	long offset;
	register int datsize;
	register int savebyte, cc;

#ifdef ISKERNEL
	u.u_segflg = 0;
#endif /* ISKERNEL */

	datsize = filep->f_datsize + 1;
	offset = longmult((recnum-1), (long)datsize);

	if (lseek(filep->f_datfd, offset, 0) != offset)
	    {
	    iserrno = errno;
	    iserrio = IO_SEEK+IO_DAT;
	    return(-1);
	    }

	savebyte = fubyte(record+datsize-1);
	cc = read(filep->f_datfd, record, datsize);
	if (cc == -1)
	    {
	    iserrno = errno;
	    iserrio = IO_READ+IO_DAT;
	    }
			 			/* deleted record ?	*/
	if (cc == datsize)
	    cc = ((fubyte(record+datsize-1) == '\n') ? 0 : -1);
	else cc = -1;
	subyte(record+datsize-1, savebyte);

	return(cc);
}

/*
 * write a data record from "record"
 */

STATIC int datawrite(record, recnum)

register char *record;
long recnum;
{
	long offset;
	register int datsize;
	register int savebyte;

#ifdef ISKERNEL
	u.u_segflg = 0;
#endif /* ISKERNEL */

	datsize = filep->f_datsize + 1;

	savebyte = fubyte(record+datsize-1);
	subyte(record+datsize-1, '\n');		/* insert record term	*/

	offset = longmult((recnum-1), (long)datsize);

	if (lseek(filep->f_datfd, offset, 0) != offset)
	    {
	    iserrno = errno;
	    iserrio = IO_SEEK+IO_DAT;
	    }
	else if (write(filep->f_datfd, record, datsize) != datsize)
	    {
	    iserrno = errno;
	    iserrio = IO_WRIT+IO_DAT;
	    }

	subyte(record+datsize-1, savebyte);
	return(iserrno ? -1 : 0);
}

/*
 * delete a data record
 */

STATIC int datadelete(recnum)

long recnum;
{
	long offset;
	register int datsize;
#ifdef ISKERNEL
	register int zerosiz;
	char zeros[128];
#endif /* ISKERNEL */

	datsize = filep->f_datsize + 1;

#ifdef ISKERNEL
	byfill(zeros, 128, 0);
	for (zerosiz = 0; zerosiz < datsize; zerosiz += 128)
	    copyout(zeros, temprecord+zerosiz, 128);
	u.u_segflg = 0;
#else
	byfill(temprecord, (datsize+1)&~1, 0);	/* clear temp record	*/
#endif /* ISKERNEL */

	offset = longmult((recnum-1), (long)datsize);

	if (lseek(filep->f_datfd, offset, 0) != offset)
	    {
	    iserrno = errno;
	    iserrio = IO_SEEK+IO_DAT;
	    }
	else if (write(filep->f_datfd, temprecord, datsize) != datsize)
	    {
	    iserrno = errno;
	    iserrio = IO_WRIT+IO_DAT;
	    }
	return(iserrno ? -1 : 0);
}

#ifdef NOLOCK			/* single-user, no locking at all */
STATIC int lksemaphore()	{ return(0); }
STATIC int lkopenlock()	{ return(0); }
STATIC int lkrecord()	{ return(0); }
STATIC int lkfile()	{ return(0); }
#endif

